package task

import (
	"cron-go/internal/pkg/crontab/dao"
	"cron-go/internal/pkg/crontab/models"
	"fmt"
	"time"

	"github.com/jakecoffman/cron"
	"github.com/ouqiang/goutil"
)

var (
	// 定时任务调度管理器
	ServiceCron *cron.Cron
	Service     *Task
)

func init() {
	Initialize()
}

// 初始化任务, 从数据库取出所有任务, 添加到定时任务并运行
func Initialize() {
	ServiceCron = cron.New()
	ServiceCron.Start()
	Service = new(Task)
}

type Task struct {
}

func CreateJob(taskModel *models.TaskMysqlModel) cron.FuncJob {
	taskFunc := func() {
		fmt.Println("[INFO] ready doing taskId:", taskModel.ID)
		// 创建新工作 worker工作
		dao.ReadyDaoServer.CreateByTaskModel(taskModel)
	}
	return taskFunc
}

// 删除任务后添加
func (task *Task) RemoveAndAdd(taskModel *models.TaskMysqlModel) {
	task.Remove(taskModel.ID)
	task.Add(taskModel)
}

func (task *Task) Remove(id int64) {
	ServiceCron.RemoveJob(fmt.Sprintf("%v", id))
}

// 直接运行任务
func (task *Task) Run(taskModel *models.TaskMysqlModel) {
	go CreateJob(taskModel)()
}

// 等待所有任务结束后退出
func (task *Task) WaitAndExit() {
	ServiceCron.Stop()
	//taskCount.Exit()
}

// 批量添加任务
func (task *Task) BatchAdd(tasks []*models.TaskMysqlModel) {
	for _, item := range tasks {
		task.RemoveAndAdd(item)
	}
}

func (task *Task) BatchRemove(tasks []*models.TaskMysqlModel) {
	for _, item := range tasks {
		task.Remove(item.ID)
	}
}

// 添加任务
func (task *Task) Add(taskModel *models.TaskMysqlModel) {
	taskFunc := CreateJob(taskModel)
	if taskFunc == nil {
		fmt.Printf("创建任务处理Job失败,不支持的任务协议:%+v \n", taskModel.ID)
		return
	}
	cronName := fmt.Sprintf("%v", taskModel.ID)
	err := goutil.PanicToError(func() {
		ServiceCron.AddFunc(taskModel.Spec, taskFunc, cronName)
	})
	if err != nil {
		fmt.Println("添加任务到调度器失败#", err)
	}
}

func AddFunc(spec string, cmd func(), name string) {
	err := goutil.PanicToError(func() {
		ServiceCron.AddFunc(spec, cmd, name)
	})
	if err != nil {
		fmt.Println("添加任务到调度器失败#", err)
	}
}

func NextRunTime(spec string, now time.Time) time.Time {
	p := cron.Parse(spec)
	// t1 := time.Now()
	// if now == nil {
	// 	t1 = now
	// }
	t1 := p.Next(now)
	return t1
}

func NextRunTimeInt64(spec string, now time.Time) int64 {
	p := cron.Parse(spec)
	t1 := p.Next(now)
	return t1.Unix()
}
